﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChainAnalises.Classes.DivizionToAccords;
using ChainAnalises.Classes.IntervalAnalysis;
using ChainAnalises.Classes.IntervalAnalysis.Characteristics;
using Segmentator.Interfaces;

namespace Segmentator.Dividers
{
    /// <summary>
    /// Компанует данные для вывода на Device
    /// </summary>
    class BaseCharacteristic: CalculatorResults
    {
        /// <summary>
        /// Словарь результатов сегментирования Название характеристики - значение
        /// </summary>
        private Dictionary<string, double> ResultCharacteristic; 
        /// <summary>
        /// Словарь Алфавит - число вхождений
        /// </summary>
        private Dictionary<string, int> Dictionary;
        /// <summary>
        /// Словарь Название входного параметра - значение
        /// </summary>
        private Dictionary<string, string> InputCharacteristic;

        public BaseCharacteristic(Chain chainFirst, Chain chain, AlphabetChain alphabetChain, double threshold)
            : base(chainFirst, chain, alphabetChain, threshold)
        {

        }
        public BaseCharacteristic(CalculatorResults calculatorResults)
            : base(calculatorResults.Chain,calculatorResults.SlotChain, calculatorResults.Alphabet, calculatorResults.Threshold)
        {
        }

        /// <summary>
        /// Формирует результирующие данные сегментации как Название - значение
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public BaseCharacteristic Format(IDataLoader input)
        {
            FormatInputData(input);
            FormatResults();
            FormatDictionary();

            return this;
        }
        /// <summary>
        /// Вормирует выходные характеристики
        /// </summary>
        private void FormatResults()
        {
            double H;
            double L;
            double g;
            double r;
            double G;

            ResultCharacteristic = new Dictionary<string, double>();
            H = GetEntropy(Algorithm._linkUp, SlotChain);
            ResultCharacteristic.Add(Algorithm.ENTROPY_OUT, H);

            L = GetAmountOfInformation(Algorithm._linkUp, SlotChain);
            ResultCharacteristic.Add(Algorithm.AMOUNT_OF_INFORMATION_OUT, H * L);

            g = GetChainRemoteness(Algorithm._linkUp, SlotChain);
            ResultCharacteristic.Add(Algorithm.REMOTENESS_OUT, g);

            r = GetChainRegularity(Algorithm._linkUp, SlotChain);
            ResultCharacteristic.Add(Algorithm.REGULARITY_OUT, r);

            G = GetChainGamut(Algorithm._linkUp, SlotChain);
            ResultCharacteristic.Add(Algorithm.GAMUT_OUT, G);

            ResultCharacteristic.Add(Algorithm.THEORETICAL_VOLUME, GetTheoryVolumeOfAlphabet());
            ResultCharacteristic.Add(Algorithm.PRACTICAL_VOLUME, GetEmpiricalVolumeOfAlphabet());
            ResultCharacteristic.Add(Algorithm.THRESHOLD, Threshold);


            H = GetEntropy(Algorithm._linkUp, Chain);
            ResultCharacteristic.Add(Algorithm.ENTROPY_IN, H);

            L = GetAmountOfInformation(Algorithm._linkUp, Chain);
            ResultCharacteristic.Add(Algorithm.AMOUNT_OF_INFORMATION_IN, H * L);

            g = GetChainRemoteness(Algorithm._linkUp, Chain);
            ResultCharacteristic.Add(Algorithm.REMOTENESS_IN, g);

            r = GetChainRegularity(Algorithm._linkUp, Chain);
            ResultCharacteristic.Add(Algorithm.REGULARITY_IN, r);

            G = GetChainGamut(Algorithm._linkUp, Chain);
            ResultCharacteristic.Add(Algorithm.GAMUT_IN, G);

        }
        /// <summary>
        /// Формирует словарь
        /// </summary>
        private void FormatDictionary()
        {
            int repeats;
            Dictionary = new Dictionary<string, int>();
            repeats = 0;

            for (int i = 0; i < SlotChain.Alpahbet.power; i++)
            {
                repeats = (int) SlotChain.UniformChain(SlotChain.Alpahbet[i]).GetCharacteristic(Algorithm._linkUp, CharacteristicsFactory.IntervalsCount);
                Dictionary.Add(SlotChain.Alpahbet[i].ToString(), repeats);                 
            }
        }
        /// <summary>
        /// Формирует входные данные
        /// </summary>
        /// <param name="input"></param>
        private void FormatInputData(IDataLoader input)
        {
            InputCharacteristic = new Dictionary<string, string>();

            InputCharacteristic.Add(Algorithm.THRESHOLD_LEFT, input.GetThresholdLeft().ToString());
            InputCharacteristic.Add(Algorithm.THRESHOLD_RIGHT, input.GetThresholdRight().ToString());
            InputCharacteristic.Add(Algorithm.STEP_THRESHOLD, input.GetThresholdStep().ToString());
            InputCharacteristic.Add(Algorithm.BALANCE, input.GetBalanceFactor().ToString());
            InputCharacteristic.Add(Algorithm.START_LENGTH_WINDOW, input.GetLengthStartWindow().ToString());
            InputCharacteristic.Add(Algorithm.CHAIN_NAME, input.GetChainName());
            InputCharacteristic.Add(Algorithm.SEQUENCE, input.GetSequence());
            InputCharacteristic.Add(Algorithm.MIN_ALPHABET_DISTORTION, input.GetMinAlphabetsDistortion().ToString());
            InputCharacteristic.Add(Algorithm.PRECISION, input.GetPrecision().ToString());
            InputCharacteristic.Add(Algorithm.AMOUNT_START_ALGORITHM, input.GetAmountStartAlgorithm().ToString());
        }

        public Dictionary<string, double> GetCaracteristic()
        {
            return ResultCharacteristic;
        }

        public Dictionary<string, int> GetDictionary()
        {
            return Dictionary;
        }

        public Dictionary<string, string> GetInputCharacteristic()
        {
            return InputCharacteristic;
        }

        public List<string> GetAlphabet()
        {
            List<string> alphabet = new List<string>();
            foreach (string chain in Dictionary.Keys)
            {
                alphabet.Add(chain);
            }
            return alphabet;
        }
    }
}
